﻿/*
 * 作者：新生命开发团队（http://www.newlifex.com/）
 * 
 * 版权：版权所有 (C) 新生命开发团队 2002-2014
 * 
 * 修改：海洋饼干（cuteant@outlook.com）
*/

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using CuteAnt.Reflection;

namespace CuteAnt.Serialization
{
	/// <summary>写入器基类</summary>
	/// <remarks>
	/// 序列化框架的核心思想：基本类型直接写入，自定义类型反射得到成员，逐层递归写入！详见<see cref="IReaderWriter" />
	///
	/// 序列化框架的处理顺序为：<see cref="IAccessor" />接口 => <see cref="OnObjectWriting" />事件 => 扩展类型 => <see cref="WriteValue(Object)" />基础类型 => <see cref="WriteDictionary" />字典 => <see cref="WriteEnumerable" />枚举 => <see cref="WriteSerializable" />序列化接口 => <see cref="WriteCustomObject" />自定义对象 => <see cref="WriteUnKnown" />未知类型 => <see cref="OnObjectWrited" />事件
	///
	/// 序列化对象时只能调用<see cref="WriteObject(Object)" />方法，其它所有方法（包括所有Write重载）仅用于内部写入或者自定义序列化时使用。
	///
	/// Decimal转为四个Int32整数输出；
	/// DateTime转为Int64输出。
	/// </remarks>
	/// <typeparam name="TSettings">设置类</typeparam>
	public abstract class WriterBase<TSettings> : ReaderWriterBase<TSettings>, IWriter2 where TSettings : ReaderWriterSetting, new()
	{
		#region 基元类型

		#region 字节

		/// <summary>将一个无符号字节写入</summary>
		/// <param name="value">要写入的无符号字节。</param>
		public abstract void Write(Byte value);

		/// <summary>将字节数组写入，如果设置了UseSize，则先写入数组长度。</summary>
		/// <param name="buffer">包含要写入的数据的字节数组。</param>
		public virtual void Write(byte[] buffer)
		{
			if (buffer == null)
			{
				WriteSize(0);
				return;
			}

			WriteSize(buffer.Length);
			Write(buffer, 0, buffer.Length);
		}

		/// <summary>将一个有符号字节写入当前流，并将流的位置提升 1 个字节。</summary>
		/// <param name="value">要写入的有符号字节。</param>
		public virtual void Write(sbyte value)
		{
			Write((Byte)value);
		}

		/// <summary>将字节数组部分写入当前流，不写入数组长度。</summary>
		/// <param name="buffer">包含要写入的数据的字节数组。</param>
		/// <param name="index">buffer 中开始写入的起始点。</param>
		/// <param name="count">要写入的字节数。</param>
		public virtual void Write(byte[] buffer, int index, int count)
		{
			if (buffer == null || buffer.Length < 1 || count <= 0 || index >= buffer.Length) return;

			for (int i = 0; i < count && index + i < buffer.Length; i++)
			{
				Write(buffer[index + i]);
			}
		}

		/// <summary>写入字节数组，自动计算长度</summary>
		/// <param name="buffer">缓冲区</param>
		/// <param name="count">数量</param>
		private void Write(Byte[] buffer, Int32 count)
		{
			if (buffer == null) return;

			if (count < 0 || count > buffer.Length) count = buffer.Length;

			Write(buffer, 0, count);
		}

		#endregion

		#region 有符号整数

		/// <summary>将 2 字节有符号整数写入当前流，并将流的位置提升 2 个字节。</summary>
		/// <param name="value">要写入的 2 字节有符号整数。</param>
		public abstract void Write(short value);

		/// <summary>将 4 字节有符号整数写入当前流，并将流的位置提升 4 个字节。</summary>
		/// <param name="value">要写入的 4 字节有符号整数。</param>
		public abstract void Write(int value);

		/// <summary>将 8 字节有符号整数写入当前流，并将流的位置提升 8 个字节。</summary>
		/// <param name="value">要写入的 8 字节有符号整数。</param>
		public abstract void Write(long value);

		#endregion

		#region 无符号整数

		/// <summary>将 2 字节无符号整数写入当前流，并将流的位置提升 2 个字节。</summary>
		/// <param name="value">要写入的 2 字节无符号整数。</param>
		//[CLSCompliant(false)]
		public virtual void Write(ushort value)
		{
			Write((Int16)value);
		}

		/// <summary>将 4 字节无符号整数写入当前流，并将流的位置提升 4 个字节。</summary>
		/// <param name="value">要写入的 4 字节无符号整数。</param>
		//[CLSCompliant(false)]
		public virtual void Write(uint value)
		{
			Write((Int32)value);
		}

		/// <summary>将 8 字节无符号整数写入当前流，并将流的位置提升 8 个字节。</summary>
		/// <param name="value">要写入的 8 字节无符号整数。</param>
		//[CLSCompliant(false)]
		public virtual void Write(ulong value)
		{
			Write((Int64)value);
		}

		#endregion

		#region 浮点数

		/// <summary>将 4 字节浮点值写入当前流，并将流的位置提升 4 个字节。</summary>
		/// <param name="value">要写入的 4 字节浮点值。</param>
		public virtual void Write(float value)
		{
			Write(BitConverter.GetBytes(value), -1);
		}

		/// <summary>将 8 字节浮点值写入当前流，并将流的位置提升 8 个字节。</summary>
		/// <param name="value">要写入的 8 字节浮点值。</param>
		public virtual void Write(double value)
		{
			Write(BitConverter.GetBytes(value), -1);
		}

		#endregion

		#region 字符串

		/// <summary>将 Unicode 字符写入当前流，并根据所使用的 Encoding 和向流中写入的特定字符，提升流的当前位置。</summary>
		/// <param name="ch">要写入的非代理项 Unicode 字符。</param>
		public virtual void Write(char ch)
		{
			Write(Convert.ToByte(ch));
		}

		/// <summary>将字符数组写入当前流，并根据所使用的 Encoding 和向流中写入的特定字符，提升流的当前位置。</summary>
		/// <param name="chars">包含要写入的数据的字符数组。</param>
		public virtual void Write(char[] chars)
		{
			Write(chars, 0, chars == null ? 0 : chars.Length);
		}

		/// <summary>将字符数组部分写入当前流，并根据所使用的 Encoding（可能还根据向流中写入的特定字符），提升流的当前位置。</summary>
		/// <param name="chars">包含要写入的数据的字符数组。</param>
		/// <param name="index">chars 中开始写入的起始点。</param>
		/// <param name="count">要写入的字符数。</param>
		public virtual void Write(char[] chars, int index, int count)
		{
			if (chars == null)
			{
				WriteSize(0);
				return;
			}

			if (chars.Length < 1 || count <= 0 || index >= chars.Length)
			{
				WriteSize(0);
				return;
			}

			// 先用写入字节长度
			var buffer = Settings.Encoding.GetBytes(chars, index, count);
			Write(buffer);
		}

		/// <summary>写入字符串</summary>
		/// <param name="value">要写入的值。</param>
		public virtual void Write(string value)
		{
			Write(value == null ? null : value.ToCharArray());
		}

		#endregion

		#region 其它

		/// <summary>将单字节 Boolean 值写入</summary>
		/// <param name="value">要写入的 Boolean 值</param>
		public virtual void Write(Boolean value)
		{
			Write((Byte)(value ? 1 : 0));
		}

		/// <summary>将一个十进制值写入当前流，并将流位置提升十六个字节。</summary>
		/// <param name="value">要写入的十进制值。</param>
		public virtual void Write(decimal value)
		{
			Int32[] data = Decimal.GetBits(value);
			for (int i = 0; i < data.Length; i++)
			{
				Write(data[i]);
			}
		}

		/// <summary>将一个时间日期写入</summary>
		/// <param name="value">数值</param>
		public virtual void Write(DateTime value)
		{
			Write(Settings.ConvertDateTimeToInt64(value));
		}

		#endregion

		#endregion

		#region 基础名值

		/// <summary>写入成员名称</summary>
		/// <param name="name">名称</param>
		public virtual void WriteName(String name)
		{
		}

		/// <summary>写入值类型</summary>
		/// <param name="value">数值</param>
		/// <returns></returns>
		public Boolean WriteValue(Object value)
		{
			return WriteValue(value, null);
		}

		/// <summary>写入值类型，只能识别基础类型，对于不能识别的类型，方法返回false</summary>
		/// <param name="value">要写入的对象</param>
		/// <param name="type">要写入的对象类型</param>
		/// <returns>是否写入成功</returns>
		protected virtual Boolean WriteValue(Object value, Type type)
		{
			if (type == null)
			{
				if (value == null) return false;
				type = value.GetType();
			}

			switch (Type.GetTypeCode(type))
			{
				case TypeCode.Boolean:
					Write((Boolean)value);
					return true;
				case TypeCode.Byte:
					Write((Byte)value);
					return true;
				case TypeCode.Char:
					Write((Char)value);
					return true;
				case TypeCode.DBNull:
					Write((Byte)0);
					return true;
				case TypeCode.DateTime:
					Write((DateTime)value);
					return true;
				case TypeCode.Decimal:
					Write((Decimal)value);
					return true;
				case TypeCode.Double:
					Write((Double)value);
					return true;
				case TypeCode.Empty:
					Write((Byte)0);
					return true;
				case TypeCode.Int16:
					Write((Int16)value);
					return true;
				case TypeCode.Int32:
					Write((Int32)value);
					return true;
				case TypeCode.Int64:
					Write((Int64)value);
					return true;
				case TypeCode.Object:
					break;

				case TypeCode.SByte:
					Write((SByte)value);
					return true;
				case TypeCode.Single:
					Write((Single)value);
					return true;
				case TypeCode.String:
					Write((String)value);
					return true;
				case TypeCode.UInt16:
					Write((UInt16)value);
					return true;
				case TypeCode.UInt32:
					Write((UInt32)value);
					return true;
				case TypeCode.UInt64:
					Write((UInt64)value);
					return true;
				default:
					break;
			}

			if (type == typeof(Guid))
			{
				Write((Guid)value);
				return true;
			}

			return false;
		}

		/// <summary>写入Guid</summary>
		/// <param name="value">数值</param>
		public virtual void Write(Guid value)
		{
			Write(value.ToByteArray(), -1);
		}

		#endregion

		#region 字典

		/// <summary>写入枚举类型数据</summary>
		/// <param name="value">枚举数据</param>
		/// <returns>是否写入成功</returns>
		public Boolean Write(IDictionary value)
		{
			return WriteDictionary(value, null, WriteMember);
		}

		/// <summary>写入字典类型数据</summary>
		/// <param name="value">字典数据</param>
		/// <param name="type">要写入的对象类型</param>
		/// <param name="callback">处理成员的方法</param>
		/// <returns>是否写入成功</returns>
		public virtual Boolean WriteDictionary(IDictionary value, Type type, WriteObjectCallback callback)
		{
			if (value == null) return true;

			// type = CheckAndWriteType("WriteDictionaryType", value, type);

			// 计算元素类型
			Type keyType = null;
			Type valueType = null;

			// 取得键值类型
			//if (!GetDictionaryEntryType(type, ref keyType, ref valueType)) return false;
			GetDictionaryEntryType(type, ref keyType, ref valueType);

			WriteSize(value.Count);
			if (value.Count == 0) return true;

			//type = value.GetType();
			if (type != null && !typeof(IDictionary).IsAssignableFrom(type)) throw new InvalidOperationException("目标类型不是字典类型！");

			Int32 i = 0;
			foreach (DictionaryEntry item in value)
			{
				Depth++;
				if (!WriteKeyValue(item, keyType, valueType, i++, callback)) return false;
				Depth--;
			}

			return true;
		}

		/// <summary>写入字典项</summary>
		/// <param name="value">对象</param>
		/// <param name="keyType">键类型</param>
		/// <param name="valueType">值类型</param>
		/// <param name="index">成员索引</param>
		/// <param name="callback">使用指定委托方法处理复杂数据</param>
		/// <returns>是否写入成功</returns>
		protected virtual Boolean WriteKeyValue(DictionaryEntry value, Type keyType, Type valueType, Int32 index, WriteObjectCallback callback)
		{
			// 如果无法取得字典项类型，则每个键值都单独写入类型
			//keyType = CheckAndWriteType("WriteKeyType", value.Key, keyType);
			if (!WriteObject(value.Key, keyType, callback)) return false;

			// valueType = CheckAndWriteType("WriteValueType", value.Value, valueType);
			if (!WriteObject(value.Value, valueType, callback)) return false;

			return true;
		}

		/// <summary>取得字典的键值类型，默认只支持获取两个泛型参数的字典的键值类型</summary>
		/// <param name="type">字典类型</param>
		/// <param name="keyType">键类型</param>
		/// <param name="valueType">值类型</param>
		/// <returns>是否获取成功，如果失败，则字典读取失败</returns>
		protected virtual Boolean GetDictionaryEntryType(Type type, ref Type keyType, ref Type valueType)
		{
			// 两个泛型参数的泛型
			if (type.IsGenericType)
			{
				Type[] ts = type.GetGenericArguments();
				if (ts != null && ts.Length == 2)
				{
					keyType = ts[0];
					valueType = ts[1];

					return true;
				}
			}

			return false;
		}

		#endregion

		#region 枚举

		/// <summary>写入枚举类型数据</summary>
		/// <param name="value">枚举数据</param>
		/// <returns>是否写入成功</returns>
		public Boolean Write(IEnumerable value)
		{
			return WriteEnumerable(value, null, WriteMember);
		}

		/// <summary>写入枚举数据，复杂类型使用委托方法进行处理</summary>
		/// <param name="value">对象</param>
		/// <param name="type">类型</param>
		/// <param name="callback">使用指定委托方法处理复杂数据</param>
		/// <returns>是否写入成功</returns>
		public virtual Boolean WriteEnumerable(IEnumerable value, Type type, WriteObjectCallback callback)
		{
			if (value == null) return true;

			type = CheckAndWriteType("WriteEnumerableType", value, type);

			//type = value.GetType();
			if (type != null && !typeof(IEnumerable).IsAssignableFrom(type)) throw new InvalidOperationException("目标类型不是枚举类型！");

			// 计算元素类型，如果无法计算，这里不能处理，否则能写不能读（因为不知道元素类型）
			var elementType = type.GetElementTypeEx();

			//if (elementType == null) return false;

			Int32 i = 0;
			foreach (var item in value)
			{
				Depth++;
				if (!WriteItem(item, elementType, i++, callback)) return false;
				Depth--;
			}
			return true;
		}

		/// <summary>写入枚举项</summary>
		/// <param name="value">对象</param>
		/// <param name="type">元素类型</param>
		/// <param name="index">元素索引</param>
		/// <param name="callback">使用指定委托方法处理复杂数据</param>
		/// <returns>是否写入成功</returns>
		protected virtual Boolean WriteItem(Object value, Type type, Int32 index, WriteObjectCallback callback)
		{
			// 如果无法取得元素类型，则每个元素都单独写入类型
			// type = CheckAndWriteType("WriteItemType", value, type);
			return WriteObject(value, type, callback);
		}

		#endregion

		#region 序列化接口

		/// <summary>写入实现了可序列化接口的对象</summary>
		/// <param name="value">要写入的对象</param>
		/// <param name="type">要写入的对象类型</param>
		/// <param name="callback">处理成员的方法</param>
		/// <returns>是否写入成功</returns>
		public virtual Boolean WriteSerializable(Object value, Type type, WriteObjectCallback callback)
		{
			if (!typeof(ISerializable).IsAssignableFrom(type)) return false;

			WriteLog("WriteSerializable", type.Name);

			return WriteCustomObject(value, type, callback);
		}

		#endregion

		#region 未知对象

		/// <summary>写入未知对象（其它所有方法都无法识别的对象），采用BinaryFormatter或者XmlSerialization</summary>
		/// <param name="value">要写入的对象</param>
		/// <param name="type">要写入的对象类型</param>
		/// <param name="callback">处理成员的方法</param>
		/// <returns>是否写入成功</returns>
		public virtual Boolean WriteUnKnown(Object value, Type type, WriteObjectCallback callback)
		{
			WriteLog("WriteUnKnown", type.Name);

			// 调用.Net的二进制序列化来解决剩下的事情
			var bf = new BinaryFormatter();
			var ms = new MemoryStream();
			bf.Serialize(ms, value);
			ms.Position = 0;
			Write(ms.ToArray());

			return true;
		}

		#endregion

		#region 扩展处理类型

		/// <summary>扩展写入，反射查找合适的写入方法</summary>
		/// <param name="value">数值</param>
		/// <param name="type">类型</param>
		/// <returns></returns>
		protected virtual Boolean WriteExtend(Object value, Type type)
		{
			if (type == typeof(Byte[]))
			{
				Write((Byte[])value);
				return true;
			}
			if (type == typeof(Char[]))
			{
				Write((Char[])value);
				return true;
			}

			//! 所有扩展类型的写入，分为Write和OnWrite两部分，Write供外部独立调用，单独提供对象引用，而OnWrite不写对象引用
			//if (type == typeof(Guid))
			//{
			//    OnWrite((Guid)value);
			//    return true;
			//}
			if (type == typeof(IPAddress))
			{
				OnWrite((IPAddress)value);
				return true;
			}
			if (type == typeof(IPEndPoint))
			{
				OnWrite((IPEndPoint)value);
				return true;
			}
			if (typeof(Type).IsAssignableFrom(type))
			{
				OnWrite((Type)value);
				return true;
			}

			return false;
		}

		/// <summary>写入IPAddress</summary>
		/// <param name="value">数值</param>
		public void Write(IPAddress value)
		{
			if (!WriteObjRef(value)) OnWrite(value);
		}

		/// <summary>写入IPAddress</summary>
		/// <param name="value">数值</param>
		protected virtual void OnWrite(IPAddress value)
		{
			// 考虑到IPv4和IPv6，地址的字节数不是固定的，所以必须先写大小
			// 然后如果为空，写大小0刚好合适
			if (value == null)
			{
				WriteSize(0);
				return;
			}
			Write((value as IPAddress).GetAddressBytes());
		}

		/// <summary>写入IPEndPoint</summary>
		/// <param name="value">数值</param>
		public void Write(IPEndPoint value)
		{
			if (!WriteObjRef(value)) OnWrite(value);
		}

		/// <summary>写入IPEndPoint</summary>
		/// <param name="value">数值</param>
		protected virtual void OnWrite(IPEndPoint value)
		{
			// 有可能value不为空而value.Address为空，导致读取失败，但这种可能性太低了，可以不考虑
			if (value == null)
			{
				WriteSize(0);
				return;
			}

			//! 直接调用OnWrite，不写对象引用，将来可能得考虑写对象引用
			OnWrite(value.Address);
			//// 端口实际只占2字节
			//Write((UInt16)value.Port);
			Write(value.Port);
		}

		/// <summary>写入Type</summary>
		/// <param name="value">数值</param>
		public void Write(Type value)
		{
			if (!WriteObjRef(value)) OnWrite(value);
		}

		/// <summary>写入Type</summary>
		/// <param name="value">数值</param>
		protected virtual void OnWrite(Type value)
		{
			if (value == null)
			{
				WriteSize(0);
				return;
			}
			Depth++;
			WriteLog("WriteType", value == null ? "" : value.FullName);

			// 分离出去，便于重载，而又能有效利用对象引用
			OnWriteType(value);
			Depth--;
		}

		/// <summary>写入Type</summary>
		/// <param name="value">数值</param>
		protected virtual void OnWriteType(Type value)
		{
			// 尽管使用AssemblyQualifiedName更精确，但是它的长度实在太大了
			if (Settings.UseTypeFullName)
				Write(value.AssemblyQualifiedName);
			else
				Write(value.FullName);
		}

		/// <summary>检查对象类型与指定写入类型是否一致</summary>
		/// <remarks>
		/// 检查对象类型与指定写入类型是否一致，若不一致，则先写入类型，以保证读取的时候能够以正确的类型读取。同时返回对象实际类型。
		/// 若想不写对象类型，可以提前设定精确类型。
		/// </remarks>
		/// <param name="action"></param>
		/// <param name="value">数值</param>
		/// <param name="type">类型</param>
		/// <returns></returns>
		protected Type CheckAndWriteType(String action, Object value, Type type)
		{
			if (type == null && value == null) return null;

			// 若想不写对象类型，可以提前设定精确类型
			if (!IsExactType(type))
			{
				if (value != null) type = value.GetType();
				WriteLog(action, type.Name);
				WriteObjectType(type);
			}

			return type;
		}

		/// <summary>写对象类型</summary>
		/// <param name="type">类型</param>
		protected virtual void WriteObjectType(Type type)
		{
			Write(type);
		}

		#endregion

		#region 复杂对象

		/// <summary>主要入口方法。把对象写入数据流</summary>
		/// <param name="value">对象</param>
		/// <returns>是否写入成功</returns>
		public Boolean WriteObject(Object value)
		{
			return WriteObject(value, null, WriteMember);
		}

		/// <summary>主要入口方法。</summary>
		/// <remarks>把目标对象指定成员写入数据流，处理基础类型、特殊类型、基础类型数组、特殊类型数组，通过委托方法处理成员</remarks>
		/// <param name="value">要写入的对象</param>
		/// <param name="type">要写入的对象类型</param>
		/// <param name="callback">处理成员的方法</param>
		/// <returns>是否写入成功</returns>
		public Boolean WriteObject(Object value, Type type, WriteObjectCallback callback)
		{
			if (type == null && value != null) type = value.GetType();
			if (callback == null) callback = WriteMember;

			// 检查IAcessor接口
			var accessor = value as IAccessor;
			if (accessor != null && accessor.Write(this)) return true;

			var rs = WriteObjectWithEvent(value, type, callback);

			// 检查IAcessor接口
			if (accessor != null) rs = accessor.WriteComplete(this, rs);

			return rs;
		}

		private Boolean WriteObjectWithEvent(Object value, Type type, WriteObjectCallback callback)
		{
			// 事件
			WriteObjectEventArgs e = null;
			if (OnObjectWriting != null)
			{
				e = new WriteObjectEventArgs(value, type, callback);

				OnObjectWriting(this, e);

				// 事件处理器可能已经成功写入对象
				if (e.Success) return true;

				// 事件里面有可能改变了参数
				value = e.Value;
				type = e.Type;
				callback = e.Callback;
			}

			var rs = OnWriteObject(value, type, callback);

			// 事件
			if (OnObjectWrited != null)
			{
				if (e == null) e = new WriteObjectEventArgs(value, type, callback);
				e.Success = rs;

				OnObjectWrited(this, e);

				// 事件处理器可以影响结果
				rs = e.Success;
			}

			return rs;
		}

		/// <summary>把目标对象指定成员写入数据流，处理基础类型、特殊类型、基础类型数组、特殊类型数组，通过委托方法处理成员</summary>
		/// <param name="value">要写入的对象</param>
		/// <param name="type">要写入的对象类型</param>
		/// <param name="callback">处理成员的方法</param>
		/// <returns>是否写入成功</returns>
		protected virtual Boolean OnWriteObject(Object value, Type type, WriteObjectCallback callback)
		{
			//! 2011-05-27 17:33
			//! 精确类型，直接写入值
			//! 未知类型，写对象引用，写类型，写对象

			if (IsExactType(type))
			{
				// 基本类型
				if (WriteValue(value, type)) return true;

				// 写入对象引用
				if (WriteObjRef(value)) return true;

				//// 引用对象为空，写入0
				//if (value == null)
				//{
				//    WriteLog("WriteNull");

				//    // 顶级不需要
				//    if (Depth > 1) WriteSize(0);
				//    return true;
				//}

				// 扩展类型
				if (WriteExtend(value, type)) return true;

				// 写入引用对象
				if (WriteRefObject(value, type, callback)) return true;
			}
			else
			{
				// 写入对象引用
				if (WriteObjRef(value)) return true;

				//// 引用对象为空，写入0
				//if (value == null)
				//{
				//    WriteLog("WriteNull");

				//    // 顶级不需要
				//    if (Depth > 1) WriteSize(0);
				//    return true;
				//}

				// 写对象类型时增加缩进，避免写顶级对象类型的对象引用时无法写入（Depth=1的对象是不写对象引用的）
				Depth++;
				type = CheckAndWriteType("WriteObjectType", value, type);
				Depth--;

				// 基本类型
				if (WriteValue(value, type)) return true;

				// 扩展类型
				if (WriteExtend(value, type)) return true;

				// 写入引用对象
				if (WriteRefObject(value, type, callback)) return true;
			}

			return true;
		}

		/// <summary>写入引用对象</summary>
		/// <param name="value">要写入的对象</param>
		/// <param name="type">要写入的对象类型</param>
		/// <param name="callback">处理成员的方法</param>
		/// <returns>是否写入成功</returns>
		protected virtual Boolean WriteRefObject(Object value, Type type, WriteObjectCallback callback)
		{
			// 字典
			if (typeof(IDictionary).IsAssignableFrom(type))
			{
				WriteLog("WriteDictionary", type.Name);

				if (WriteDictionary(value as IDictionary, type, callback)) return true;
			}

			// 枚举
			if (typeof(IEnumerable).IsAssignableFrom(type))
			{
				WriteLog("WriteEnumerable", type.Name);

				if (WriteEnumerable(value as IEnumerable, type, callback)) return true;
			}

			// 可序列化接口
			if (WriteSerializable(value, type, callback)) return true;

			// 复杂类型，处理对象成员
			var old = CurrentObject;
			CurrentObject = value;
			if (WriteCustomObject(value, type, callback))
			{
				CurrentObject = old;
				return true;
			}
			CurrentObject = old;

			return WriteUnKnown(value, type, callback);
		}

		private List<Object> objRefs = new List<Object>();

		/// <summary>写入对象引用。</summary>
		/// <param name="value">对象</param>
		/// <returns>是否写入成功</returns>
		public virtual Boolean WriteObjRef(Object value)
		{
			if (!Settings.UseObjRef) return false;

			if (value == null)
			{
				WriteLog("WriteObjRef", "null");

				// 顶级不需要
				if (Depth > 1) OnWriteObjRefIndex(0);
				return true;
			}

			// 在对象引用集合中找该对象
			var index = objRefs.IndexOf(value);

			// 如果没找到，添加，返回false，通知上层继续处理
			if (index < 0)
			{
				objRefs.Add(value);

				WriteLog("AddObjRef", objRefs.Count, value.ToString(), value.GetType().Name);

				// 写入引用计数
				if (Depth > 1) OnWriteObjRefIndex(objRefs.Count);

				return false;
			}

			WriteLog("WriteObjRef", index + 1, value.ToString(), value.GetType().Name);

			// 如果找到，写入对象引用计数，返回true，通知上层不要再处理该对象，避免重写写入对象
			OnWriteObjRefIndex(index + 1);

			return true;
		}

		/// <summary>写对象引用计数</summary>
		/// <param name="index"></param>
		protected virtual void OnWriteObjRefIndex(Int32 index)
		{
			WriteSize(index);
		}

		#endregion

		#region 自定义对象

		/// <summary>写自定义对象</summary>
		/// <param name="value">要写入的对象</param>
		/// <param name="type">要写入的对象类型</param>
		/// <param name="callback">处理成员的方法</param>
		/// <returns>是否写入成功</returns>
		public virtual Boolean WriteCustomObject(Object value, Type type, WriteObjectCallback callback)
		{
			if (value == null) return true;
			if (callback == null) callback = WriteMember;

			var mis = GetMembers(type, value);
			if (mis == null || mis.Length < 1) return true;

			// 调试输出成员列表
			if (Debug) ShowMembers("WriteCustomObject", mis);

			for (int i = 0; i < mis.Length; i++)
			{
				var member = mis[i];
				var v = member[value];

				Depth++;

				// 基础类型输出日志时，同时输出值，更直观
				if (Type.GetTypeCode(mis[i].Type) == TypeCode.Object)
					WriteLog("WriteMember", member.Name, member.Type.Name);
				else
					WriteLog("WriteMember", member.Name, member.Type.Name, v);

				var old = CurrentMember;
				CurrentMember = member;
#if !DEBUG
				try
#endif
				{
					if (!WriteMember(member.Name, v, member.Type, i, callback))
					{
						CurrentMember = old;
						return false;
					}

					CurrentMember = old;
				}
#if !DEBUG
				catch (Exception ex)
				{
					throw new XSerializationException(member.Name, ex);
				}
#endif

				Depth--;
			}

			return true;
		}

		/// <summary>写入对象成员</summary>
		/// <param name="name">成员名字</param>
		/// <param name="value">要写入的对象</param>
		/// <param name="type">要写入的成员类型</param>
		/// <param name="index">成员索引</param>
		/// <param name="callback">处理成员的方法</param>
		/// <returns>是否写入成功</returns>
		public Boolean WriteMember(String name, Object value, Type type, Int32 index, WriteObjectCallback callback)
		{
			if (callback == null) callback = WriteMember;

			// 写入成员前
			WriteMemberEventArgs e = null;
			if (OnMemberWriting != null)
			{
				e = new WriteMemberEventArgs(name, value, type, index, callback);

				OnMemberWriting(this, e);

				// 事件处理器可能已经成功写入对象
				if (e.Success) return true;

				// 事件里面有可能改变了参数
				value = e.Value;
				type = e.Type;
				index = e.Index;
				callback = e.Callback;
			}

			var rs = OnWriteMember(name, value, type, index, callback);

			// 写入成员后
			if (OnMemberWrited != null)
			{
				e = new WriteMemberEventArgs(name, value, type, index, callback);
				e.Success = rs;

				OnMemberWrited(this, e);

				// 事件处理器可以影响结果
				rs = e.Success;
			}

			return rs;
		}

		/// <summary>写入对象成员</summary>
		/// <param name="name">成员名字</param>
		/// <param name="value">要写入的对象</param>
		/// <param name="type">要写入的成员类型</param>
		/// <param name="index">成员索引</param>
		/// <param name="callback">处理成员的方法</param>
		/// <returns>是否写入成功</returns>
		protected virtual Boolean OnWriteMember(String name, Object value, Type type, Int32 index, WriteObjectCallback callback)
		{
			WriteName(name);
			return callback(this, value, type, callback);
		}

		private static Boolean WriteMember(IWriter writer, Object value, Type type, WriteObjectCallback callback)
		{
			return writer.WriteObject(value, type, callback);
		}

		#endregion

		#region 事件

		/// <summary>写对象前触发。</summary>
		public event EventHandler<WriteObjectEventArgs> OnObjectWriting;

		/// <summary>写对象后触发。</summary>
		public event EventHandler<WriteObjectEventArgs> OnObjectWrited;

		/// <summary>写成员前触发。</summary>
		public event EventHandler<WriteMemberEventArgs> OnMemberWriting;

		/// <summary>写成员后触发。</summary>
		public event EventHandler<WriteMemberEventArgs> OnMemberWrited;

		#endregion

		#region 方法

		/// <summary>写入大小</summary>
		/// <param name="size"></param>
		public void WriteSize(Int32 size)
		{
			if (!UseSize) return;

			WriteLog("WriteSize", size);

			OnWriteSize(size);
		}

		/// <summary>写入大小</summary>
		/// <param name="size"></param>
		protected virtual void OnWriteSize(Int32 size)
		{
			switch (Settings.SizeFormat)
			{
				case TypeCode.Int16:
				case TypeCode.UInt16:
					Write((Int16)size);
					break;

				case TypeCode.Int32:
				case TypeCode.UInt32:
				case TypeCode.Int64:
				case TypeCode.UInt64:
				default:
					Write(size);
					break;
			}
		}

		/// <summary>写入长度。多维数组用</summary>
		/// <param name="lengths"></param>
		protected virtual void WriteLengths(string lengths)
		{
			//if (!UseSize) return;

			WriteLog("WriteLengths", lengths);

			Write(lengths);
		}

		/// <summary>刷新缓存中的数据</summary>
		public virtual void Flush()
		{
			Stream.Flush();
		}

		/// <summary>如果设置了自动刷新缓存，该方面将会调用Flush</summary>
		protected void AutoFlush()
		{
			if (Settings.AutoFlush) Flush();
		}

		/// <summary>重置</summary>
		public override void Reset()
		{
			objRefs.Clear();

			base.Reset();
		}

		// 耗时且影响数据流，慎用！
		///// <summary>输出数据转为字节数组。耗时且影响数据流，慎用！</summary>
		///// <returns></returns>
		//public virtual Byte[] ToArray()
		//{
		//    Flush();

		//    Stream stream = Stream;
		//    if (stream is MemoryStream) return (stream as MemoryStream).ToArray();

		//    if (!stream.CanRead) return null;

		//    // 移动指针到开头
		//    Int64 p = stream.Length;
		//    if (stream.CanSeek) stream.Seek(0, SeekOrigin.Begin);

		//    // 把数据复制出来
		//    var buffer = stream.ReadBytes();
		//    if (stream.CanSeek) stream.Seek(p, SeekOrigin.Begin);

		//    return buffer;
		//}

		// 耗时且影响数据流，慎用！
		///// <summary>已重载。</summary>
		///// <returns></returns>
		//public override string ToString()
		//{
		//    Byte[] buffer = ToArray();
		//    if (buffer == null || buffer.Length < 1) return base.ToString();

		//    return Settings.Encoding.GetString(buffer);
		//}

		#endregion
	}
}